/*
 * Copyright (c) 2005 -2008 Reliable Source, Inc. and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Mozilla Public License v.1.1,
 * BSD, and Eclipse Public License v1.0 which accompanies this
 * distribution and is available at:
 *
 * 		http://www.eclipse.org/legal/epl-v10.html
 * 		http://www.opensource.org/licenses/bsd-license.php
 * 		http://www.mozilla.org/MPL/MPL-1.1.html
 *
 * Contributors:
 *     IBM Corporation	     -  http://ibm.com
 *     	- initial API and implementation
 *
 *     patientos.org         - http://patientos.org
 *     	- domain and database persistence layer
 *
 *     Reliable Source, Inc. - http://reliablesource.org
 *     	- Symbiosys Application Framework,
 *     	- Symbiosys Application, Symbiosys Product
 *
 */
package org.reliablesource.symbiosys.workbench.tests.handlers;

import junit.framework.Assert;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IHandler;
import org.eclipse.core.commands.NotEnabledException;
import org.eclipse.core.commands.NotHandledException;
import org.eclipse.core.commands.common.NotDefinedException;
import org.eclipse.core.commands.contexts.Context;

import org.eclipse.ui.ISources;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.contexts.IContextActivation;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.handlers.IHandlerActivation;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.services.IServiceLocator;
import org.eclipse.ui.tests.harness.util.UITestCase;

import org.reliablesource.client.ui.workbench.views.ReliableOpenListener;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 *
 * HandlerActivationTest.java<br>
 * Created on: Jun 27, 2008<br>
 *
 * @author <a href="mailto:dennis.park@gmail.com">Dennis Park</a>
 *
 * @category
 * @since 1.0
 */
public class HandlerActivationTest extends UITestCase {
    public static final String PERSPECTIVE_ID = "com.cisco.nm.cmp.client.ui.test.ContextTestPerspective";
    public static final String ROOT_CXT = IContextService.CONTEXT_ID_WINDOW;
    public static final String WB_CXT = "com.cisco.nm.cmp.client.ui.workbench";
    public static final String WB_WIN_CXT = WB_CXT + ".window";
    public static final String PART_CXT = WB_WIN_CXT + ".part"; //	public static final String NAV_CXT = WB_WIN_CXT + ".nav"; 
    public static final String ASV_CXT = WB_WIN_CXT + ".asv";
    public static final String CSV_CXT = WB_WIN_CXT + ".csv"; //	public static final String ANCHOR_CXT = WB_WIN_CXT + ".anchor"; 
    public static final String VWR_CXT = PART_CXT + ".viewer";
    public static final String[] KNOWN_CONTEXTS = {
            ROOT_CXT, WB_CXT, PART_CXT, ASV_CXT, CSV_CXT, VWR_CXT
        }; //, NAV_CXT}; 
    public static final String ACTIVE_CXT_ID = WB_CXT +
        ISources.ACTIVE_CONTEXT_NAME;
    public static final String ACTIVE_ACTIONSETS_CXT_ID = WB_CXT +
        ISources.ACTIVE_ACTION_SETS_NAME;
    public static final String ACTIVE_SHELL_CXT_ID = WB_CXT +
        ISources.ACTIVE_SHELL_NAME;
    public static final String ACTIVE_WB_WIN_SHELL_CXT_ID = WB_CXT +
        ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME;
    public static final String WB_HANDLER_ID = "HNDLR_WB";
    public static final String WB_WIN_HANDLER_ID = "HNDLR_WB_WIN"; //	public static final String NAV_HANDLER_ID = "HNDLR_NAV";
    public static final String ASV_HANDLER_ID = "HNDLR_ASV";
    public static final String CSV_HANDLER_ID = "HNDLR_CSV";
    public static final String DBL_CLKL_CMD_ID = ReliableOpenListener.DBL_CLICK_CMD;
    public static final String CMD_ID = "Test.MockCommandId";
    private ICommandService globalCommandService;
    private IContextService globalContextService;
    private IHandlerService globalHandlerService;
    private IServiceLocator services;
    private Map<String, IContextActivation> testContextActivations = new HashMap<String, IContextActivation>();
    private Map<String, IHandlerActivation> testHandlerActivations = new HashMap<String, IHandlerActivation>();
    private Map<String, IHandler> testHandlers = new HashMap<String, IHandler>();
    private List<String> contextList;

    /**
     * Constructor for <code>HandlerActivationTest</code>.
     *
     * @param name
     *            The name of the test
     */
    public HandlerActivationTest(String name) {
        super(name);
        services = PlatformUI.getWorkbench();
        globalContextService = (IContextService) services.getService(IContextService.class);
        globalCommandService = (ICommandService) services.getService(ICommandService.class);
        globalHandlerService = (IHandlerService) services.getService(IHandlerService.class);
    }

    private IContextActivation activateContext(String contextId) {
        IContextActivation c = globalContextService.activateContext(contextId);
        testContextActivations.put(contextId, c);

        return c;
    }

    /**
     * @param cmd
     * @param handlerId
     * @throws ExecutionException
     * @throws NotDefinedException
     * @throws NotEnabledException
     * @throws NotHandledException
     */
    private void assertHandlerIsExecuted(Command cmd, String handlerId)
        throws ExecutionException, NotDefinedException, NotEnabledException,
            NotHandledException {
        ActTestHandler handler = (ActTestHandler) testHandlers.get(handlerId);
        int count = handler.executionCount;
        cmd.executeWithChecks(new ExecutionEvent());
        assertEquals("The handler count should be incremented", count + 1,
            handler.executionCount);
    }

    /**
     * @param contextId
     * @param handlerId
     * @param expressionInfo
     */
    private void createHandlerActivation(String contextId, String handlerId) {
        makeHandler(handlerId, contextId);
    } /*
     * (non-Javadoc)
     *
     * @see org.eclipse.ui.tests.harness.util.UITestCase#doSetUp()
     */
    protected void doSetUp() throws Exception {
        contextList = new ArrayList<String>();

        for (int i = 0; i < KNOWN_CONTEXTS.length; i++)
            contextList.add(KNOWN_CONTEXTS[i]);

        Command cmd = globalCommandService.getCommand(CMD_ID);
        Assert.assertTrue("Error in doSetup: Command:" + CMD_ID +
            " is not defined.", cmd.isDefined()); // Verify that it is properly read in from extension point elements.

        final Context[] definedContextList = globalContextService.getDefinedContexts();

        int nContexts = definedContextList.length;

        for (int i = 0; i < nContexts; i++) {
            if (contextList.contains(definedContextList[i].getId()))
                contextList.remove(definedContextList[i].getId());
        }

        if (contextList.size() != 0) {
            for (int j = 0; j < contextList.size(); j++)
                System.err.println("Error in doSetup: Defined Contexts " +
                    contextList.get(j) +
                    " was not discovered as extension element.");

            assertTrue("Error in doSetup: Contexts are unknown.", false);
        }
    } /*
     * (non-Javadoc)
     *
     * @see org.eclipse.ui.tests.harness.util.UITestCase#doTearDown()
     */
    protected void doTearDown() throws Exception {
        contextList.clear();
        globalHandlerService.deactivateHandlers(testHandlerActivations.values());
        testHandlerActivations.clear();
        globalContextService.deactivateContexts(testContextActivations.values());
        testContextActivations.clear();
        super.doTearDown();
    }

    /**
     * @throws ExecutionException
     * @throws NotDefinedException
     * @throws NotEnabledException
     * @throws NotHandledException
     */
    private void doTestForBreak()
        throws ExecutionException, NotDefinedException, NotEnabledException,
            NotHandledException {
        Command cmd = globalCommandService.getCommand(CMD_ID);
        assertTrue("Command should be defined", cmd.isDefined());

        assertFalse("Should not be handled yet", cmd.isHandled());

        IContextActivation c1 = activateContext(WB_WIN_CXT);
        IContextActivation c2 = activateContext(ASV_CXT);
        IContextActivation c3 = activateContext(CSV_CXT);
        assertTrue("Should still be handled", cmd.isHandled());

        assertHandlerIsExecuted(cmd, CSV_HANDLER_ID);

        globalContextService.deactivateContext(c3);
        globalContextService.deactivateContext(c2);
        globalContextService.deactivateContext(c1);
    }

    /**
     * @param currentHandler
     * @param expression1
     * @return
     */
    private void makeHandler(String handler, String context) {
        IHandler currentHandler = null;

        if (!testHandlers.containsKey(handler)) {
            currentHandler = new ActTestHandler(context);
            testHandlers.put(handler, currentHandler);
        } else {
            currentHandler = (IHandler) testHandlers.get(handler);
        }

        testHandlerActivations.put(handler,
            globalHandlerService.activateHandler(CMD_ID, currentHandler));
    }

    private String[] getActiveContextIds() {
        return (String[]) globalContextService.getActiveContextIds()
                                              .toArray(new String[globalContextService.getActiveContextIds()
                                                                                      .size()]);
    }

    public void testBasicHandler() throws Exception {
        createHandlerActivation(ASV_CXT, ASV_HANDLER_ID);

        Command cmd = globalCommandService.getCommand(CMD_ID);
        assertTrue("Command should be defined", cmd.isDefined());

        assertFalse("Should not be handled yet", cmd.isHandled());

        IWorkbenchWindow window = openTestWindow(PERSPECTIVE_ID);
        IWorkbenchPage page = window.getActivePage(); //		IViewPart view = page.showView(ASVContextPart.ID);
                                                      //	Set the handler for this context.

        IHandlerActivation _handlerToken = globalHandlerService.activateHandler(CMD_ID,
                testHandlers.get(ASV_HANDLER_ID));
        cmd.setHandler(_handlerToken.getHandler());
        assertTrue("Should definitely be handled", cmd.isHandled());

        ActTestHandler handler1 = (ActTestHandler) testHandlers.get(ASV_HANDLER_ID);
        int count = handler1.executionCount;
        cmd.executeWithChecks(new ExecutionEvent());
        assertEquals("The handler count should be correct", count + 1,
            handler1.executionCount);

        assertFalse("Should not be handled", cmd.isHandled());
    }

    public void testForBreak123() throws Exception {
        createHandlerActivation(WB_WIN_CXT, WB_WIN_HANDLER_ID);
        createHandlerActivation(ASV_CXT, ASV_HANDLER_ID);
        createHandlerActivation(CSV_CXT, CSV_HANDLER_ID);

        doTestForBreak();
    }

    public void testForBreak132() throws Exception {
        createHandlerActivation(WB_WIN_CXT, WB_WIN_HANDLER_ID);
        createHandlerActivation(CSV_CXT, CSV_HANDLER_ID);
        createHandlerActivation(ASV_CXT, ASV_HANDLER_ID);

        doTestForBreak();
    }

    public void testForBreak213() throws Exception {
        createHandlerActivation(ASV_CXT, ASV_HANDLER_ID);
        createHandlerActivation(WB_WIN_CXT, WB_WIN_HANDLER_ID);
        createHandlerActivation(CSV_CXT, CSV_HANDLER_ID);

        doTestForBreak();
    }

    public void testForBreak231() throws Exception {
        createHandlerActivation(ASV_CXT, ASV_HANDLER_ID);
        createHandlerActivation(CSV_CXT, CSV_HANDLER_ID);
        createHandlerActivation(WB_WIN_CXT, WB_WIN_HANDLER_ID);

        doTestForBreak();
    }

    public void testForBreak312() throws Exception {
        createHandlerActivation(CSV_CXT, CSV_HANDLER_ID);
        createHandlerActivation(WB_WIN_CXT, WB_WIN_HANDLER_ID);
        createHandlerActivation(ASV_CXT, ASV_HANDLER_ID);

        doTestForBreak();
    }

    public void testForBreak321() throws Exception {
        createHandlerActivation(CSV_CXT, CSV_HANDLER_ID);
        createHandlerActivation(ASV_CXT, ASV_HANDLER_ID);
        createHandlerActivation(WB_WIN_CXT, WB_WIN_HANDLER_ID);
        doTestForBreak();
    }

    public void testTwoHandlers() throws Exception {
        createHandlerActivation(WB_WIN_CXT, WB_WIN_HANDLER_ID);
        createHandlerActivation(ASV_CXT, ASV_HANDLER_ID);

        Command cmd = globalCommandService.getCommand(CMD_ID);
        assertTrue("Command should be defined", cmd.isDefined());

        assertFalse("Should not be handled yet", cmd.isHandled());

        IContextActivation activationC1 = activateContext(WB_WIN_CXT);
        assertTrue("Should definitely be handled", cmd.isHandled());

        ActTestHandler handler1 = (ActTestHandler) testHandlers.get(WB_WIN_HANDLER_ID);
        int count1 = handler1.executionCount;
        cmd.executeWithChecks(new ExecutionEvent());
        assertEquals("The handler count should be incremented", count1 + 1,
            handler1.executionCount);

        activateContext(ASV_CXT);
        assertTrue("Should still be handled", cmd.isHandled());

        ActTestHandler handler2 = (ActTestHandler) testHandlers.get(ASV_HANDLER_ID);
        int count2 = handler2.executionCount;
        count1 = handler1.executionCount;
        cmd.executeWithChecks(new ExecutionEvent());
        assertEquals("The handler1 count should not be incremented", count1,
            handler1.executionCount);
        assertEquals("The handler2 count should be incremented", count2 + 1,
            handler2.executionCount);

        globalContextService.deactivateContext(activationC1);
        assertTrue("Will still be handled", cmd.isHandled());
    }

    public static class ActTestHandler extends AbstractHandler {
        public String contextId;
        public int executionCount = 0;

        public ActTestHandler(String id) {
            super();
            contextId = id;
        } /*
         * (non-Javadoc)
         *
         * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent)
         */
        public Object execute(ExecutionEvent event) {
            executionCount++;

            return null;
        }
    }
}
